Within the field of computing, “checkpointing” is a technique used to backup and restore an application or system, often in the event of failure. In many cases, checkpointing involves taking a snapshot of the current system or application state, and storing that data. If necessary, the system or application can be returned to the state it was in when the checkpoint file was created. In some cases, when creating a checkpoint of an application or process, the state of the memory allocated to that application or process essentially defines the state of the application or process. Returning the memory to the checkpointed state restores the application to the state it was in when the checkpoint was created.
When checkpointing a process, a checkpoint system handles application memory at some defined level of granularity. Often, this level of granularity is an operating system (OS) page; for purposes of discussion and illustration, OS pages will be used herein, except as noted. When performing a memory-related activity, such as detecting modified memory contents, writing memory contents to disk during a checkpoint, or reloading memory contents during a restart, memory is managed in segments of one or more memory pages.
Traditional approaches to checkpointing a process, and particularly to incrementally checkpointing a process, suffer a number of drawbacks. For example, fragmentation of a checkpoint file will occur, whenever a memory page that existed during one checkpoint is freed before the next checkpoint. The application which freed the page has no means of returning the corresponding portion of the checkpoint file to a null state, and so that portion of the file becomes an unused fragment.
Another conventional method involves storing the incremental checkpoints as a series of “patches” to the address space. At each checkpoint, the set of pages that has been modified during the preceding interval is recorded serially to disk as a patch. Each page can be stored to disk with an 8-byte offset, which describes where in the process it was located. On a restart, the patches can be applied to a blank address space in the order in which they were recorded.
The runtime complexity associated with this approach is typically low and fragmentation is substantially avoided. However, the amount of disk space required is effectively unbounded in this approach. This is because a page that is modified in every interval is recorded to disk in every interval without removing any of the prior recordings. A worst-case scenario, and one that is not uncommon in high performance computing (HPC), occurs when an application modifies all of its memory during each interval. The disk size required is bounded at O(n*m) where ‘n’ is the number of pages an application uses and ‘m’ is the number of checkpoints taken.
The advent of 64 bit computing has only exacerbated these problems, as the increase in available address space leads to much greater potential issues. For example, in a 32 bit computing environment, the total addressable memory was limited to four gigabytes (230 bytes); in a 64 bit addressing scheme, 16 exabytes (260 bytes) are available.